package com.lyx.crm.service;

import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import com.lyx.crm.base.BaseService;
import com.lyx.crm.dao.UserMapper;
import com.lyx.crm.dao.UserRoleMapper;
import com.lyx.crm.model.UserModel;
import com.lyx.crm.utils.AssertUtil;
import com.lyx.crm.utils.Md5Util;
import com.lyx.crm.utils.UserIDBase64;
import com.lyx.crm.vo.User;
import com.lyx.crm.vo.UserRole;
import lombok.extern.log4j.Log4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @Package: com.lyx.crm.service
 * @ClassName: UserService
 * @Author: lyx
 * @CreateTime: 2021/7/15 20:13
 * @Description:
 */
@Service
public class UserService extends BaseService<User, Integer> {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserRoleMapper userRoleMapper;

    /**
     * 1. 参数判断，判断用户姓名、用户密码非空弄
     * 如果参数为空，抛出异常（异常被控制层捕获并处理）
     * 2. 调用数据访问层，通过用户名查询用户记录，返回用户对象
     * 3. 判断用户对象是否为空
     * 如果对象为空，抛出异常（异常被控制层捕获并处理）
     * 4. 判断密码是否正确，比较客户端传递的用户密码与数据库中查询的用户对象中的用户密码
     * 如果密码不相等，抛出异常（异常被控制层捕获并处理）
     * 5. 如果密码正确，登录成功
     *
     * @param userName
     * @param userPwd
     */
    public UserModel userLogin(String userName, String userPwd) {
        checkLoginParam(userName, userPwd);
        //获取user对象
        User user = userMapper.queryUserByName(userName);

        AssertUtil.isTrue(user == null, "用户名不存在！");

        //判断密码是否匹配
        checkUserPwd(userPwd, user.getUserPwd());

        UserModel userModel = buildUserInfo(user);

        return userModel;

    }

    /**
     * 构建需要返回给客户端的用户对象
     *
     * @param user
     * @return
     */
    private UserModel buildUserInfo(User user) {

        UserModel userModel = new UserModel();
//        userModel.setUserId(user.getId());
        userModel.setUserIdStr(UserIDBase64.encoderUserID(user.getId()));

        userModel.setUserName(user.getUserName());
        userModel.setTrueName(user.getTrueName());
        return userModel;
    }

    /**
     * 密码判断
     * 将客户端的密码加密，在于数据库中的密码对比
     *
     * @param userPwd
     * @param password
     * @return
     */
    private void checkUserPwd(String userPwd, String password) {

        userPwd = Md5Util.encode(userPwd);

        Log.get().info("数据库密码 ：" + password);
        Log.get().info("输入密码 ：" + userPwd);
        AssertUtil.isTrue(!StrUtil.equals(userPwd, password), "密码不正确！");
    }

    /**
     * 如果参数为空，向controller抛出异常
     *
     * @param userName
     * @param passWord
     */
    public void checkLoginParam(String userName, String passWord) {
        //验证账号
        AssertUtil.isTrue(StrUtil.isBlank(userName), "用户名不能为空！");
        //验证密码
        AssertUtil.isTrue(StrUtil.isBlank(passWord), "密码不能为空！");

    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void updatePassWord(Integer userId, String oldPwd, String newPwd, String repeatPwd) {
        //查询user对象
        User user = userMapper.selectByPrimaryKey(userId);

        AssertUtil.isTrue(null == user, "待更新记录不存在！");
        //参数校验
        checkPassWordParams(user, oldPwd, newPwd, repeatPwd);


        //将user对象密码替换
        user.setUserPwd(Md5Util.encode(newPwd));

        //更新密码
        AssertUtil.isTrue(userMapper.updateByPrimaryKeySelective(user) < 1, "修改密码失败");
    }

    /**
     * 修改密码的参数校验
     *
     * @param user
     * @param oldPwd
     * @param newPwd
     * @param repeatPwd
     */
    private void checkPassWordParams(User user, String oldPwd, String newPwd, String repeatPwd) {
        //判断原始密码是否为空
        AssertUtil.isTrue(StrUtil.isBlank(oldPwd), "原始密码不能为空");

        //判断原始密码是否与新密码一致
        AssertUtil.isTrue((!user.getUserPwd().equals(Md5Util.encode(oldPwd))), "原始密码不正确");

        //判断新密码是否为空
        AssertUtil.isTrue(StrUtil.isBlank(newPwd), "新密码不能为空！");

        //新密码与原始密码是否一样
        AssertUtil.isTrue(oldPwd.equals(newPwd), "新密码与原始密码一致");

        //判断确认密码是否为空
        AssertUtil.isTrue(StrUtil.isBlank(repeatPwd), "确认密码不能为空！");

        //判断新密码和原始密码是否相同
        AssertUtil.isTrue(!newPwd.equals(repeatPwd), "两次密码不一样");

    }

    /**
     * 查询所有销售人员
     *
     * @return
     */
    public List<Map<String, Object>> queryAllSales() {
        return userMapper.queryAllSales();
    }

    /**
     * 添加用户
     * 1.参数校验
     * 用户名userName 非空，唯一
     * 邮箱 email 非空
     * 手机号phone 非空，格式正确
     * 2.设置参数默认值
     * isValid 1
     * createDate 系统当前时间
     * updateDate 系统当前时间
     * 默认密码  123456 ->md5加密
     *
     * @param user
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void addUser(User user) {
        //参数校验
        checkUserParams(user);

        //设置默认值
        user.setCreateDate(new Date());
        user.setUpdateDate(new Date());
        user.setIsValid(1);
        user.setUserPwd(Md5Util.encode("123456"));

        AssertUtil.isTrue(userMapper.insertSelective(user) < 1, "用户添加失败");

        /*关联角色*/
        relationUserRoles(user.getId(), user.getRoleIds());
    }

    /**
     * 1.参数校验
     * 用户名userName 非空，唯一
     * 邮箱 email 非空
     * 手机号phone 非空，格式正确
     *
     * @param user
     */
    private void checkUserParams(User user) {

        AssertUtil.isTrue(StrUtil.isBlank(user.getUserName()), "用户名不能为空");

        User user1 = userMapper.queryUserByName(user.getUserName());
        if (user.getId() == null) {
            AssertUtil.isTrue(null != user1, "用户名不唯一");
        }

        AssertUtil.isTrue(StrUtil.isBlank(user.getEmail()), "邮箱不能为空");

        AssertUtil.isTrue(StrUtil.isBlank(user.getPhone()), "手机号不能为空");

        AssertUtil.isTrue(!PhoneUtil.isMobile(user.getPhone()), "手机号格式不正确");

    }

    /**
     * 修改用户信息
     * 1.验证前端传来的参数User
     * 2.查询是否有该用户
     * 3.修改数据库
     *
     * @param user
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void updateUser(User user) {
        //1.验证前端传来的参数User
        checkUserParams(user);
        AssertUtil.isTrue(user.getId() == null, "用户id为空");

        User user1 = userMapper.selectByPrimaryKey(user.getId());
        AssertUtil.isTrue(user1 == null, "该用户不存在");

        //合并前端传来的user到user1
        mergeUser(user, user1);
        user1.setUpdateDate(new Date());
        AssertUtil.isTrue(userMapper.updateByPrimaryKeySelective(user1) != 1, "用户修改失败");

        /*关联角色*/
        relationUserRoles(user.getId(), user.getRoleIds());
    }

    /**
     * 删除用户id下的所有角色，在将传来的ids关联到用户表上
     *
     * @param userId  用户id
     * @param roleIds 角色ids
     */
    private void relationUserRoles(Integer userId, String roleIds) {
        //通过用户id查询角色记录
        Integer count = userRoleMapper.countUserRoleByUserId(userId);
        //如果角色记录存在，删除全部
        if (count > 0) {
            AssertUtil.isTrue(!userRoleMapper.deleteUserRoleByUserId(userId).equals(count), "用户角色分配失败");
        }

        //判断角色id是否存在，如果存在就添加
        if (!StrUtil.isBlank(roleIds)) {
            List<UserRole> userRoleList = new ArrayList<>();

            String[] roleIdsArray = roleIds.split(",");

            for (String roleId : roleIdsArray) {
                UserRole userRole = new UserRole();
                userRole.setRoleId(Integer.parseInt(roleId));
                userRole.setUserId(userId);
                userRole.setUpdateDate(new Date());
                userRole.setCreateDate(new Date());
                //存在list中
                userRoleList.add(userRole);
            }
            //批量添加用户角色记录
            AssertUtil.isTrue(userRoleMapper.insertBatch(userRoleList) != userRoleList.size(), "用户角色分配失败");
        }

    }

    private void mergeUser(User user, User user1) {

        if (user.getId() != null && !StrUtil.equals(user1.getId().toString(), user.getId().toString())) {
            user1.setId(user.getId());
        }
        if (user.getPhone() != null && !StrUtil.equals(user1.getPhone(), user.getPhone())) {
            user1.setPhone(user.getPhone());
        }
        if (user.getEmail() != null && !StrUtil.equals(user1.getEmail(), user.getEmail())) {
            user1.setEmail(user.getEmail());
        }
        if (user.getUserName() != null && !StrUtil.equals(user1.getUserName(), user.getUserName())) {
            user1.setUserName(user.getUserName());
        }
        if (user.getUserPwd() != null && !StrUtil.equals(user1.getUserPwd(), user.getUserPwd())) {
            user1.setUserPwd(user.getUserPwd());
        }

        if (user.getTrueName() != null && !StrUtil.equals(user.getTrueName(), user1.getTrueName())) {
            user1.setTrueName(user.getTrueName());
        }
        if (user.getUpdateDate() != null && !StrUtil.equals(user1.getUpdateDate().toString(), user.getUpdateDate().toString())) {
            user1.setUpdateDate(user.getUpdateDate());
        }

        if (user.getRoleIds() != null && !StrUtil.equals(user1.getRoleIds(), user.getRoleIds())) {
            user1.setRoleIds(user.getRoleIds());
        }
    }

    /**
     * 用户删除
     *
     * @param ids
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void deleteByIds(Integer[] ids) {
        //判断ids是否为空
        AssertUtil.isTrue(ids == null || ids.length == 0, "待删除记录不存在");

        //执行删除操作判断受影响行数
        AssertUtil.isTrue(userMapper.deleteBatch(ids) != ids.length, "删除失败");

        /*删除用户关联的角色*/
        for (Integer userId : ids) {
            Integer count = userRoleMapper.countUserRoleByUserId(userId);
            if (count > 0) {
                AssertUtil.isTrue(!userRoleMapper.deleteUserRoleByUserId(userId).equals(count), "角色关联删除失败");
            }
        }
    }
}
